home *** CD-ROM | disk | FTP | other *** search
- /*
- SNEWS 2.00
-
- unbatch - quick and dirty news toss, no feeding of other sites
-
-
- Copyright (C) 1991 John McCombs, Christchurch, NEW ZEALAND
- john@ahuriri.gen.nz
- PO Box 2708, Christchurch, NEW ZEALAND
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License, version 1, as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- See the file COPYING, which contains a copy of the GNU General
- Public License.
-
-
- USAGE: unbatch {[-a] [-n] [-v] [-i] [-j] [-f] [-l] [-s] [-d]}
- -a means add any news groups found
- -n means decompress the first batch, then stop before tossing
- -v means verbose, tell what we are doing
- -i means query for adding any new groups found
- -j means junk, don't add to junk if posted elsewhere
- -f means filter, filter out non printable characters
- -l means ignore length in headers
- -s means don't check for free space
- -x means run Snews on successful end
- -d means force unbatch to process on disk
-
- NOTE: for the Atari version the meaning of the -f and -l switches
- have been reversed.
-
- -f means do not filter out non-printable characters
- -l means do not ignore lengths in headers
-
- I have done this because the previous action was causing
- problems (bus errors) and I do not have time to investigate
- why.
-
-
- */
- /*---------------------------- Source Control ------------------------------*/
-
- /*
- * $Id: UNBATCH.C,v 1.2 1994/02/05 18:50:32 gbj Exp user $
- */
-
-
- /****************************************************************************
- * 20 May 92 1.2 GT ka9q mods. *
- * 08 Jun 92 1.3 GT FQDN in "Path:". *
- * Fix disc space check. *
- * 09 Jun 92 1.4 GT Only expand "Path:" in header. *
- * 12 Jun 92 1.5 NJL Check for duplicate articles; add verbose mode; *
- * restructure toss(); improve performance; *
- * slightly improve #!rnews test. *
- * 24 Jun 92 1.6 GT Ensure that spool_file is open in toss (). *
- * 17 Jul 92 1.7 GT C++ compilation. *
- * 27 Jul 92 1.8 MSM Add -j option, only post to junk if not posted *
- * elsewhere. *
- * Change file I/O to binary, to allow for ^Z. *
- * Add -f option to filter non printable chars. *
- * 16 Aug 92 1.9 MSM Snews 1.9 *
- * Add article count to verbose display *
- * Check / Process lock files *
- * rfc1036 style header accepted, but not used *
- * use tmp/temp environemnt variable for spool *
- * file. *
- * 27 Aug 92 1.10 MSM Fix long newsgroup header line breaking unbatch *
- * Fix disk free check to check the drive newsbase *
- * the newsbase resides on, not the default drive. *
- * 26 Sep 92 1.11 MSM Detect and place in control group any article *
- * with a control header. *
- * 27 Nov 92 1.12 MSM Article Length display, clean up lock file on *
- * exits. *
- * 29 Dec 92 1.13 MSM Save startup environment. *
- * Check article length when available but add -l *
- * flag to disable checks. *
- * Add new groups found in newsbatches to newsbase *
- * Clean up exit when history.snw not found *
- * Change option messages *
- * Make checking of free space optional *
- * 1 Feb 93 1.14 MSM Change code to access temporary files *
- * 22 Feb 93 1.15 MSM Wrong verbose article length fixed *
- * 31 May 93 1.16 MSM Snews 2.0 *
- * Fix prescan for new groups picking up from body *
- * In memory article extraction *
- * Tidy up *
- * Large article processing to disk *
- * 10 Jul 93 1.17 MSM Correct assumption about memory overhead *
- * Read only first Newsgroups: line *
- * (as requested by G.Toal) *
- * 1 Sep 93 1.18 MSM Add use disk option and history full warning *
- * 5 Sep 93 1.19 MSM Atexit added *
- * 10 Oct 93 1.20 MSM Truncate long (illegal) subject lines *
- * 18 oct 93 1.21 MSM Long integer handling tidied up *
- * Return codes added *
- * Load failure due to size of history only *
- * reported if verbose mode is on. *
- * 5 Dec 93 1.22 MSM Subject limited to 128 characters *
- * 9 Dec 93 1.23 MSM Error reporting code added *
- * 2 Apr 94 1.24 MSM Delete all lock files on error exits *
- * Account for use of memory by history list when *
- * unbatching articles *
- * 11 Jun 94 AT GBJ Reverse meaning of -l -f switches *
- ****************************************************************************/
-
- #include <ctype.h>
- #include <fcntl.h>
- #include <io.h>
- #include <process.h>
- #ifdef __TURBOC__
- # include <dir.h>
- #else
- # ifdef ATARI
- # include <sys/dir.h>
- # include <stdlib.h>
- # include <ext.h>
- # include <errno.h>
- # else
- # include <direct.h>
- # endif
- #endif
- #include "defs.h"
- #include "unbatch.h"
- #include "locking.h"
-
- #ifndef __TURBOC__
- #ifndef ATARI
- unsigned long farcoreleft(void);
- unsigned long testcoreleft(void);
- #define ffblk _find_t
- #define ff_reserved reserved
- #define ff_attrib attrib
- #define ff_ftime wr_time
- #define ff_date wr_date
- #define ff_size size
- #define ff_name name
- #define findfirst(a, b, c) _dos_findfirst(a, c, b)
- #define findnext _dos_findnext
- #define getdfree _dos_getdiskfree
- #define df_avail avail_clusters
- #define df_total total_clusters
- #define df_bsec bytes_per_sector
- #define df_sclus sectors_per_cluster
- #endif
- #endif
-
- #ifndef ATARI
- int getopt(int argc, char **argv, char *opts);
- #endif
-
- #ifdef ATARI
- extern unsigned long _STACK = 32768;
- int statx(const char *, struct stat *);
- #else
- unsigned _stklen = 16384;
- #endif
-
- INFO my_stuff;
-
- /* There are far too many statics here, it needs sorting out ! */
-
- static char buf[512], msg[256], subject[256], msg_id[256];
- static char newsgroups[512];
- static time_t t;
-
- #ifdef ATARI
- static char *Usage = "\
- Usage: unbatch [-a] [-d] [-f] [-i] [-j] [-l] [-n] [-s] [-v] [-x]\n\
- a = add automatically any new groups found in news batch\n\
- d = process via disk\n\
- f = do not filter out non printable characters\n\
- i = add interactivly any new groups found in news batch\n\
- j = don't add to junk if posted elsewhere\n\
- l = check article length\n\
- n = no unpacking to newsbase (test mode)\n\
- s = do not check for free space before unbatching\n\
- v = verbose mode\n\
- x = execute Snews on exit\n\n";
- #else
- static char *Usage = "\
- Usage: unbatch [-a] [-d] [-f] [-i] [-j] [-l] [-n] [-s] [-v] [-x]\n\
- a = add automatically any new groups found in news batch\n\
- d = process via disk\n\
- f = filter out non printable characters\n\
- i = add interactivly any new groups found in news batch\n\
- j = don't add to junk if posted elsewhere\n\
- l = don't check article length\n\
- n = no unpacking to newsbase (test mode)\n\
- s = do not check for free space before unbatching\n\
- v = verbose mode\n\
- x = execute Snews on exit\n\n";
- #endif
-
- static char verbose = 0;
-
- static char cixmode = 0;
-
- static char CrossPostToJunk = 1;
-
- static char batch_name[65] = {""};
-
- static char spool_name[65];
-
- static unsigned int article_count = 0;
-
- static unsigned int duplicate_count = 0;
-
- static unsigned int junk_count = 0;
-
- #ifdef ATARI
- static unsigned int filter_mode = 1;
- #else
- static unsigned int filter_mode = 0;
- #endif
-
- #ifdef ATARI
- static unsigned int no_length = 1;
- #else
- static unsigned int no_length = 0;
- #endif
-
- static unsigned int control_flag = 0;
-
- static unsigned long art_length = 0l;
-
- static unsigned long prev_art_length = 0l;
-
- static unsigned long art_start = 0l;
-
- static unsigned long art_end = 0l;
-
- static unsigned long art_end_calc = 0l;
-
- static unsigned long art_lines = 0l;
-
- static unsigned int interactive_add = 0;
-
- static unsigned int add_all = 0;
-
- static unsigned int space_mode = 0;
-
- static unsigned int Exec_Snews = 0;
-
- static unsigned long Free_Mem;
-
- static unsigned int disk_cnt = 0;
-
- static unsigned long MinFree = 0l;
-
- static unsigned long MaxFree = 0l;
-
- static unsigned long LargestArt = 0l;
-
- static int Via_Disk = 0;
-
- #ifdef ATARI
- extern char **environ; /* the environment */
- #endif
-
- /*------------------------------- main --------------------------------*/
- int main(int argc, char *argv[])
- {
- FILE *tmp_file, *spool_file;
- static char name[256], in_name[256];
- int ans, done, no_toss = 0;
- #ifndef ATARI
- int drive;
- #else
- dev_t drive;
- char drive_letter[]="?ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- long disk_total;
- #endif
- long required_disk, disk_free;
- struct stat st;
- #ifdef __TURBOC__
- struct dfree df;
- #else
- #ifdef ATARI
- struct dfree df;
- #else
- struct _diskfree_t df;
- #endif
- #endif
- struct ffblk ffblk;
- int c;
- int ret_code;
-
- if (fprintf(stderr, "Demon Internet Simple News v%d.%02d [build %d]\n",
- rmj, rmm, rup) == EOF)
- abort_error(1, "");
- fprintf(stderr, "Unbatch New News\n\n");
-
- atexit(end_stats);
- Free_Mem = farcoreleft();
- MinFree = MaxFree = Free_Mem;
-
- while ((c = getopt(argc, argv, "aAdDfFiIjJlLsSnNvVxX?")) != EOF)
- switch (tolower(c)) {
- case 'a':
- /* add mode */
- add_all = 1;
- interactive_add = 0;
- fprintf(stderr, "\tAll new Newsgroups will be added.\n");
- break;
- case 'd':
- /* disk mode */
- Via_Disk = 1;
- fprintf(stderr, "\tProcessing will be forced via disk.\n");
- break;
- case 'f':
- /* Filter mode */
- #ifdef ATARI
- filter_mode = 0;
- fprintf(stderr, "\tNon printing characters will not be removed.\n");
- #else
- filter_mode = 1;
- fprintf(stderr, "\tNon printing characters will be removed.\n");
- #endif
- break;
- case 'i':
- /* Interactive add new groups */
- interactive_add = 1;
- add_all = 0;
- fprintf(stderr, "\tNew Newsgroups will be added interactively.\n");
- break;
- case 'l':
- /* if TRUE then don't test article lengths */
- #ifdef ATARI
- no_length = 0;
- fprintf(stderr, "\tArticle length will be checked.\n");
- #else
- no_length = 1;
- fprintf(stderr, "\tArticle length will not be checked.\n");
- #endif
- break;
- case 'n':
- /* if TRUE, then just uncompress, don't unbatch */
- no_toss = 1;
- fprintf(stderr, "\tUncompress pass only will be run.\n");
- break;
- case 's':
- /* free space mode */
- space_mode = 1;
- fprintf(stderr, "\tFree space will not be checked.\n");
- break;
- case 'v':
- /* Verbose mode */
- verbose = 1;
- fprintf(stderr, "\tProgress will be reported verbosely.\n");
- break;
- case 'c':
- /* cix mode - no #!rnews separators (not yet implemented) */
- cixmode = 1;
- fprintf(stderr, "\tCIX mode is set on.\n");
- break;
- case 'j':
- /* Junk Mode - crosspost to junk supressed */
- CrossPostToJunk = 0;
- fprintf(stderr, "\tArticles will not be crossposted to Junk.\n");
- break;
- case 'x':
- /* Execute Snews on exit */
- Exec_Snews = 1;
- fprintf(stderr, "\tSnews will be run on successful completion.\n");
- break;
- case '?':
- fprintf(stderr, Usage);
- exit(1);
- }
-
- if (!load_stuff()) {
- fprintf(stderr, "unbatch: Couldn't read rc info\n");
- exit(1);
- }
- sprintf(in_name, "%s*.lck", my_stuff.incoming_dir);
- done = findfirst(in_name, &ffblk, 0);
- if (!done) {
- fprintf(stderr, "unbatch: Article file(s) locked!\n");
- exit(1);
- }
- sprintf(in_name, "%shistory.lck", my_stuff.news_dir);
- done = findfirst(in_name, &ffblk, 0);
- if (!done) {
- fprintf(stderr, "unbatch: History file locked!\n");
- exit(1);
- }
- sprintf(in_name, "%s*.*", my_stuff.incoming_dir);
- done = findfirst(in_name, &ffblk, 0);
- strcpy(batch_name, ffblk.ff_name);
- while (!done) {
- if (mlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch") != 0) {
- /* Fudge to avoid processing or complaining about .lck files */
- if (strstr(ffblk.ff_name, ".LCK") == NULL)
- fprintf(stderr, "unbatch: Can't lock article file %s%s\n",
- my_stuff.incoming_dir, ffblk.ff_name);
- done = findnext(&ffblk);
- }
- else
- break;
- }
-
- if (done) {
- fprintf(stderr, "unbatch: Nothing to process!\n");
- if (Exec_Snews == 1) {
- fprintf(stderr, "\n\nLoading Snews ....\n");
- #ifdef ATARI
- ans = forklpe("snews", "snews", NULL, environ);
- #else
- ans = execlp("snews", "snews", NULL);
- #endif
- fprintf(stderr, "unbatch: exec error %d\n", ans);
- }
- exit(1);
- }
-
- if (add_all != 0) /* add new groups ? */
- proc_new(ffblk.ff_name, 1);
- if (interactive_add != 0)
- proc_new(ffblk.ff_name, 2);
-
- if (mlock(my_stuff.news_dir, "history", "Unbatch") != 0) {
- fprintf(stderr, "unbatch: Can't lock history file!\n");
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- exit(1);
- }
- load_active_file();
-
- free_ng();
-
- sprintf(name, "%shistory.snw", my_stuff.news_dir);
- if ((tmp_file = fopen(name, "rb")) == NULL) {
- fprintf(stderr, "\n\rHistory file not found, create one (y/n) ? ");
- ans = getch();
- putch(ans);
- putch('\n');
- putch('\r');
- ans = tolower(ans);
- if (ans != 'y') {
- fprintf(stderr, "unbatch: No history file!\n");
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- rmlock(my_stuff.news_dir, "History", "Unbatch");
- exit(1);
- }
- tmp_file = fopen(name, "wb");
- if (tmp_file == NULL) {
- fprintf(stderr, "unbatch: Unable to create history file!\n");
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- rmlock(my_stuff.news_dir, "History", "Unbatch");
- exit(1);
- }
- }
- if (fclose(tmp_file) == EOF)
- abort_error(2, "Closing history.snw");
-
- load_history_list(0);
-
- Free_Mem = farcoreleft();
- if ((Free_Mem < HIST_MEM_LIMIT) && (verbose == 1)) {
- fprintf(stderr, "unbatch: Insufficient memory to load entire history\n");
- fprintf(stderr, " duplicate articles may not be detected. Proceed (y/n) ? ");
- ans = getch();
- ans = toupper(ans);
- putch(ans);
- putch('\n');
- putch('\r');
- if (ans != 'Y') {
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- rmlock(my_stuff.news_dir, "History", "Unbatch");
- exit(1);
- }
- }
- MinFree = Free_Mem;
- MaxFree = Free_Mem;
- Free_Mem = ((Free_Mem) / 3l);
- if (Free_Mem < 16384l) {
- fprintf(stderr, "unbatch: Insufficient memory available!\n");
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- rmlock(my_stuff.news_dir, "History", "Unbatch");
- exit(1);
- }
-
- sprintf(spool_name, "%s\\$$item", my_stuff.temp_name);
- if ((spool_file = fopen(spool_name, "w+b")) == NULL) {
- fprintf(stderr, "unbatch: Unable to create temporary file!\n");
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- rmlock(my_stuff.news_dir, "History", "Unbatch");
- exit(1);
- }
-
- if (fclose(spool_file) == EOF) /* we may never use it ! */
- abort_error(3, "Closing temporary spool file");
- if (unlink(spool_name) != 0)
- abort_error(4, "Deleting temporary spool file");
-
-
- while (!done) {
-
- sprintf(name, "%s%s", my_stuff.incoming_dir, ffblk.ff_name);
- fprintf(stderr, "unbatch: processing %s\n", name);
-
- /*
- * Check for enough room. We need:
- *
- * - more than twice the size of the batch for uncompressed batch,
- * say 1.2 * space for the articles.
- *
- * For example a 100k batch may require 280kb for the uncompressed
- * batch, then another 280 kb for the articles.
- *
- * Of course the above does not apply to non-compressed batches
- * I reckon 1.2 times the size should do, allowing for slack.
- */
-
- if (space_mode == 0) {
-
- if (statx(name, &st) != 0)
- abort_error(5, "Determining drive status");
-
- required_disk = (long)((float) st.st_size * 1.2);
-
- strcpy(name, getenv("SNEWS"));
- if (strlen(name) > 3) {
- if (name[strlen(name)-1] == '\\')
- name[strlen(name)-1] = '\0';
- }
- strcat(name, "\\snews.rc");
-
- if(statx(name, &st) != 0)
- abort_error(6, "Determine drive status");
-
- drive = st.st_dev;
- getdfree(drive + 1, &df);
- if (df.df_sclus == 0xffff)
- abort_error(7, "Determine disk space");
- disk_free = (long) df.df_avail * (long) df.df_bsec *
- (long) df.df_sclus;
- #ifdef ATARI
- disk_total = (long)df.df_total * (long)df.df_bsec *
- (long)df.df_sclus;
- printf("unbatch: Drive %c: avail %ldK, total %ldK\n",
- drive_letter[st.st_dev+1], disk_free/1024, disk_total/1024);
- #endif
- if (disk_free < required_disk) {
- fprintf(stderr, "unbatch: %ld bytes of disk req'd to unpack batch\n",
- required_disk);
- fprintf(stderr, "unbatch: only %ld bytes of disk space available\n",
- disk_free);
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- rmlock(my_stuff.news_dir, "History", "Unbatch");
- exit(1);
- }
- }
- /* uncompress the news batch and return a pointer to the temp file */
-
- sprintf(name, "%s%s", my_stuff.incoming_dir, ffblk.ff_name);
-
- if ((tmp_file = decode_batches(name, no_toss)) != NULL) {
-
- open_hist_file();
- toss(tmp_file);
- close_hist_file();
- fclose(tmp_file);
-
- if (unlink(name) != 0) {
- sprintf(buf, "deleting file %s", name);
- abort_error(8, buf);
- }
- sprintf(name, "%s\\$$item", my_stuff.temp_name);
- unlink(name);
-
- }
- else {
- fprintf(stderr, "unbatch: could not unpack compressed news batch %s\n", name);
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- rmlock(my_stuff.news_dir, "History", "Unbatch");
- exit(1);
- }
- rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
- while ((done = findnext(&ffblk)) == 0) {
- if (mlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch") != 0) {
- /* Fudge to avoid processing or complaining about .lck files */
- if (strstr(ffblk.ff_name, ".LCK") == NULL)
- fprintf(stderr, "unbatch: Unable to lock article file %s%s\n",
- my_stuff.incoming_dir, ffblk.ff_name);
- }
- else
- break;
- }
-
- }
-
- close_active_file();
- free_hist_list();
- rmlock(my_stuff.news_dir, "history", "Unbatch");
-
- if (Exec_Snews == 1) {
- fprintf(stderr, "\n\nLoading Snews ....\n");
- #ifdef ATARI
- ans = forklpe("snews", "snews", NULL, environ);
- #else
- ans = execlp("snews", "snews", NULL);
- #endif
- fprintf(stderr, "unbatch: exec error %d\n", ans);
- }
- ret_code = 0;
- return ret_code;
- }
-
- /*---------------------------- Error Handler -------------------------------*/
- void abort_error(int numb, char *text)
- {
- char *buffer;
-
- rmlock(my_stuff.news_dir, "history", "Unbatch");
- rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
- printf("\n\n");
- printf("unbatch: A fatal error occurred, error #%d\n", numb);
- printf(" %s\n", text);
- printf(" errno is %d\n", errno);
- buffer = strerror(errno);
- printf(" %s\n\n", buffer);
- printf("Unbatch did not complete successfully\n\n");
- if (fcloseall() == EOF)
- printf("Some files were not successfully closed\n\n");
- exit(2);
- }
-
- /*----------------------------- Ending Stats -------------------------------*/
- void end_stats()
- {
- fprintf(stderr, "unbatch: complete, %u articles, %u duplicates, %u via disk, %u junked\n",
- article_count, duplicate_count, disk_cnt, junk_count);
- fprintf(stderr, " Initial free memory %lu, minimum free memory %lu\n",
- MaxFree, MinFree);
- fprintf(stderr, " Memory used %lu largest article was %lu\n", MaxFree-MinFree,
- LargestArt);
- }
-
- /*--------------------------- post article work file to all groups ----*/
- LINES *post_to_groups(LINES * spool, FILE *spool_file)
- {
- FILE *out_file = NULL;
- LINES *help;
- static char nglist[512], junk_test[512];
- long where;
- ACTIVE *gp;
- char *p;
- int junk_flag; /* nz - junk to junk group */
- int already_junked; /* nz - message already junked */
-
- already_junked = 0;
- nglist[0] = '\0';
-
- if ((spool == NULL) && (spool_file == NULL))
- return NULL;
-
- if (strlen(newsgroups) != 0) {
-
- if (verbose) {
- if (art_length > 0)
- fprintf(stderr, "%4.4u %5.5ld bytes, Message-ID: %s\n",
- article_count, prev_art_length, msg_id);
- else
- fprintf(stderr, "%4.4u, Message-ID: %s\n", article_count, msg_id);
- }
- /* Check if we've already got this message from another feed */
- /* Shouldn't happen with NNTP, but can do with UUCP or CIX */
- if (find_msg_id(msg_id) == NULL) {
- if (control_flag == TRUE)
- strcpy(newsgroups, "Newsgroups: control");
- strcpy(junk_test, newsgroups);
-
- /* If junk flag set, step through newsgroups line to see if */
- /* this article is to be posted to an active group. If so */
- /* set already_junked to prevent crossposting to junk. */
-
- if (!CrossPostToJunk) {
- p = strtok(junk_test, " \t\r\n,:");
- p = strtok(NULL, " \t\r\n,:");
- while (p != '\0') {
- gp = find_news_group(p, &junk_flag);
- if (junk_flag == 0) { /* Posting to active group */
- already_junked = 1; /* No need to post to junk */
- break;
- }
- p = strtok(NULL, " \t\r\n,:");
- }
- strcpy(junk_test, newsgroups);
- /* if omitting a group then don't place in nglist */
- p = strtok(junk_test, " \t\r\n,:");
- p = strtok(NULL, " \t\r\n,:");
- if (already_junked == 0)
- strcpy(nglist, newsgroups + 11);
- else {
- while (p != '\0') {
- gp = find_news_group(p, &junk_flag);
- if (junk_flag == 0)
- strcat(nglist, p);
- p = strtok(NULL, " \t\r\n,:");
- if ((p != '\0') && (junk_flag == 0))
- strcat(nglist, ",");
- }
- strcat(nglist, "\n");
- }
- }
- else
- strcpy(nglist, newsgroups + 11);
-
- /* Step through the list of newsgroups */
-
- p = strtok(newsgroups, " \t\r\n,:");
- p = strtok(NULL, " \t\r\n,:");
-
- /*
- * For each newsgroup
- * - open the text file
- * - save the file pointer
- * - append the message to it
- * - close the file
- * - open the index file
- * - save the file pointer and the subject line
- */
-
- if (verbose)
- fputc('\t', stderr);
-
- while (p != '\x00') {
-
- out_file = open_out_file(p, &junk_flag);
-
- if (verbose) {
- if (junk_flag)
- fprintf(stderr, " (%s)", p);
- else
- fprintf(stderr, " %s ", p);
- }
- if (junk_flag != 0) {
- /* Check to see if we have already posted this in "junk". */
-
- if (already_junked == 0) {
- already_junked = 1;
- junk_count++;
- }
- else {
- /* Already posted in junk - skip it. */
-
- if (fclose(out_file) == EOF) { /* skip this */
- sprintf(buf, "closing %s", p);
- abort_error(10, buf);
- }
-
-
- /* Reset the high message number. */
-
- gp = find_news_group(p, &junk_flag);
- (gp->hi_num)--;
- update_active_entry(gp);
- p = strtok(NULL, " \t\r\n,:"); /* next group */
- continue;
- }
-
- } /* if (junk_flag != 0) */
-
- where = ftell(out_file);
- if (where == -1l) {
- sprintf(buf, "getting pointer in %s", p);
- abort_error(11, buf);
- }
- if (spool != NULL) {
- for (help = spool; help != NULL; help = help->next)
- if (fputs(help->data, out_file) == EOF) {
- sprintf(buf, "writing to %s", p);
- abort_error(12, buf);
- }
- }
- else {
- rewind(spool_file);
- while (fgets(buf, 511, spool_file) != NULL)
- if (fputs(buf, out_file) == EOF) {
- sprintf(buf, "writing to %s", p);
- abort_error(13, buf);
- }
- }
- if (fprintf(out_file, "\n@@@@END\n") == EOF) {
- sprintf(buf, "writing to %s", p);
- abort_error(13, buf);
- }
- if (fclose(out_file) == EOF) {
- sprintf(buf, "closing file %s", p);
- abort_error(15, buf);
- }
-
- out_file = open_index_file(p);
- gp = find_news_group(p, &junk_flag);
- if (fprintf(out_file, "%08ld %08ld %09ld %s", where,
- gp->hi_num, t, subject) == EOF) {
- sprintf(buf, "writing to %s", p);
- abort_error(16, buf);
- }
- if (fclose(out_file) == EOF) {
- sprintf(buf, "closing %s", p);
- abort_error(17, buf);
- }
- Free_Mem -= 3 * (sizeof(HIST_LIST)); /* account for history in memory */
-
- p = strtok(NULL, " \t\r\n,:");
- }
- if (verbose)
- fputc('\n', stderr);
- add_hist_record(msg_id, nglist);
- if (spool == NULL)
- disk_cnt++;
- }
- else {
- if (verbose)
- fprintf(stderr, "\tDuplicate article\n");
- duplicate_count++;
- }
- }
- if (MinFree > farcoreleft())
- MinFree = farcoreleft();
- if (spool != NULL) {
- while (spool) {
- help = spool;
- spool = spool->next;
- free(help->data);
- free(help);
- }
- }
- else {
- if (fclose(spool_file) == EOF)
- abort_error(18, spool_name);
- if (unlink(spool_name) == -1)
- abort_error(19, spool_name);
- spool_file = NULL;
- }
- return spool; /* == NULL */
- }
-
- /*--------------------------- unpack the batch ------------------------*/
- void toss(FILE * tmp_file)
- {
-
- /*
- * Toss it into the appropriate files.
- *
- */
-
- LINES *spool = NULL, *help;
- FILE *spool_file = NULL;
- char *p;
- int /* already_junked, */ in_header;
- int token, first_token;
- int on_disk = 0;
- char buf2[512];
-
-
- strcpy(msg_id, "");
- strcpy(subject, "-- no subject --\n");
- strcpy(newsgroups, "");
-
- rewind(tmp_file);
- time(&t);
- in_header = TRUE;
-
- /* set a large disk transfer buffer */
- /* read the file */
- first_token = 0;
- while (fgets(buf, 511, tmp_file) != NULL) {
-
- if (!filter_mode)
- remcr(buf);
- else
- filter(buf);
-
- /*
- * Check for a line containing only the Rnews token or rfc1036 style
- * token + count.
- * This is still liable to abuse but not so much so as accepting that
- * token *anywhere* in the line, like it used to do.
- *
- * art_length is losely checked to see it the Rnews token is at the
- * expected place in the file. If no the token is assumed to be part
- * of an article.
- *
- * The test could still be made more secure (i.e. if the count is
- * there, ensure nothing else follows it).
- */
-
- token = 0;
-
- prev_art_length = art_length;
- if (prev_art_length > LargestArt)
- LargestArt = prev_art_length;
-
- if (strncmp(buf, "#! rnews", 8) == 0 &&
- ((strcspn(buf + 8, "\r\n") == 0) ||
- ((art_length = atol(buf + 8)) != 0l)))
- token = 1; /* Token found */
-
- if ((first_token == 0) && token == 1) {
- art_start = ftell(tmp_file);
- art_end_calc = art_start + art_length;
- }
- if (first_token != 0) {
- if ((no_length == 0) && (token == 1) &&
- (((art_end_calc + art_lines - 1) - 10) > art_end))
- token = 0; /* Token not within 10 bytes of correct place */
- }
- else {
- first_token = 1;
- }
-
- if (token == 1) {
-
- art_start = ftell(tmp_file);
- art_end_calc = art_start + art_length;
- art_lines = 0l;
- if ((art_length > Free_Mem) || (art_length == 0l) || (Via_Disk != 0))
- on_disk = 1;
- else
- on_disk = 0; /* this one to 0 */
- spool = post_to_groups(spool, spool_file);
- spool_file = NULL;
- article_count++;
-
- strcpy(subject, "-- no subject --\n");
- strcpy(newsgroups, "");
- in_header = TRUE;
- control_flag = FALSE;
-
- }
- else {
- /* flag the end of the header */
- if (strcmp(buf, "\n") == 0)
- in_header = FALSE;
-
- /* save the newsgroups line */
- if (in_header) {
- if (strnicmp(buf, "Message-ID:", 11) == 0) {
- strcpy(msg, buf);
- p = strtok(msg, " \t\r\n");
- p = strtok(NULL, " \t\r\n");
- strcpy(msg_id, p);
- }
- if ((strnicmp(buf, "Newsgroups:", 11) == 0) && (newsgroups[0] == '\0'))
- strcpy(newsgroups, buf);
- if (strnicmp(buf, "Control:", 8) == 0)
- control_flag = TRUE;
- if (strnicmp(buf, "Subject:", 8) == 0) {
- if (strlen(buf) > 136) {
- buf[136] = '\n';
- buf[137] = '\0';
- }
- strcpy(subject, buf + 8);
- }
- /* add our system name to the path list */
- if (strnicmp(buf, "Path:", 5) == 0) {
- p = strtok(buf, " \t");
- p = strtok(NULL, " \t");
- sprintf(buf2, "Path: %s.%s!%s", my_stuff.my_site,
- my_stuff.my_domain, p);
- if (on_disk == 0) {
- if (spool == NULL)
- spool = help = (LINES *) malloc(sizeof(LINES));
- else {
- help->next = (LINES *) malloc(sizeof(LINES));
- help = help->next;
- }
- help->next = NULL;
- help->data = (char *) malloc(strlen(buf2) + 1);
- strcpy(help->data, buf2);
- }
- else {
- if (spool_file == NULL)
- spool_file = fopen(spool_name, "w+b");
- if (spool_file == NULL) {
- sprintf(buf, "opening to %s", spool_name);
- abort_error(20, buf);
- }
- if (fprintf(spool_file, "%s", buf2) == EOF) {
- sprintf(buf, "writing to %s", spool_name);
- abort_error(21, buf);
- }
- }
- }
- else {
- if (on_disk == 0) {
- if (spool == NULL)
- spool = help = (LINES *) malloc(sizeof(LINES));
- else {
- help->next = (LINES *) malloc(sizeof(LINES));
- help = help->next;
- }
- help->next = NULL;
- help->data = (char *) malloc(strlen(buf) + 1);
- strcpy(help->data, buf);
- }
- else {
- if (spool_file == NULL)
- spool_file = fopen(spool_name, "w+b");
- if (spool_file == NULL) {
- sprintf(buf, "opening file %s", spool_name);
- abort_error(22, buf);
- }
- if (fprintf(spool_file, "%s", buf) == EOF) {
- sprintf(buf, "writing to %s", spool_name);
- abort_error(122, buf);
- }
- }
- }
- }
- /* if (in_header) */
- else {
- if (on_disk == 0) {
- if (spool == NULL)
- spool = help = (LINES *) malloc(sizeof(LINES));
- else {
- help->next = (LINES *) malloc(sizeof(LINES));
- help = help->next;
- }
- help->next = NULL;
- help->data = (char *) malloc(strlen(buf) + 1);
- strcpy(help->data, buf);
-
- }
- else {
- if (spool_file == NULL)
- spool_file = fopen(spool_name, "w+b");
- if (spool_file == NULL) {
- sprintf(buf, "opening file %s", spool_name);
- abort_error(23, buf);
- }
- if (fprintf(spool_file, "%s", buf) == EOF) {
- sprintf(buf, "writing to %s", spool_name);
- abort_error(24, buf);
- }
- }
- }
- }
- art_lines++;
- art_end = ftell(tmp_file);
- if (art_end == -1l)
- abort_error(25, "seeking in temporary file");
- }
-
- /* process the last one */
-
- spool = post_to_groups(spool, spool_file);
-
- }
-
- /*--------------------------- unpack the batch ------------------------*/
- FILE *decode_batches(char *fn, int no_toss)
- {
-
- /*
- * take the batch, strip off the !cunbatch, and feed the file to uncompress,
- * the opened uncompressed file is returned
- */
-
- FILE *out_file;
- size_t bufsize;
-
- if (no_toss)
- return (NULL);
-
- /* open the uncompressed */
-
- if ((out_file = fopen(fn, "rb")) == NULL) {
- (void) printf("unbatch: cannot open uncompressed file %s\n", fn);
- return (NULL);
- }
- /* set a large disk transfer buffer */
- for (bufsize = (size_t) 32768U;
- setvbuf(out_file, NULL, _IOFBF, bufsize) != 0 && bufsize > 512;
- bufsize /= 2)
- /* do nothing */ ;
-
- return (out_file);
- } /* FILE *decode_batches (char *fn, int no_toss) */
-
-
- /*------------------------- remove CR's from buffer ------------------------*/
- void remcr(char *buf)
- {
- char *s, *d;
-
- s = d = buf;
-
- do {
- if (*s != 0x0d)
- *d++ = *s;
- }
- while (*s++ != '\0');
- }
-
- /*------------------- remove non printables from buffer --------------------*/
- void filter(char *buf)
- {
- char *s, *d;
-
- s = d = buf;
-
- do {
- if (*s != 0) {
- if (*s < 0x20) /* Since BC is signed char will get >0x80 as well */
- if ((*s != '\t') && (*s != '\n') && (*s != '\f') && (*s != '\r'))
- *s = '?';
- }
- if (*s != 0x0d)
- *d++ = *s;
- }
- while (*s++ != '\0');
- }
-
- /*------------------- Process any new groups in batch ----------------------*/
-
- static NEW_GROUP *added, *added_first;
-
- void proc_new(char *f, int t)
- {
-
- FILE *batch_file;
- int junk_flag, already_junked, count, in_header;
- char batch_name[80];
- char buf[512], junk_test[512], nglist[512], *p;
- size_t bufsize;
- ACTIVE *gp;
-
- fprintf(stderr, "\nChecking %s for new newsgroups...", f);
- if (t == 1)
- fprintf(stderr, "\nAny found will be added to the newsbase\n\n");
- if (t == 2)
- fprintf(stderr, "\nYou will be asked if you wish to add any found\n\n");
-
- load_active_file();
-
- free_ng();
- strcpy(batch_name, my_stuff.incoming_dir);
- strcat(batch_name, f);
- if ((batch_file = fopen(batch_name, "r")) == NULL) {
- fprintf(stderr, "Unable to open batch file %s for processing\n", f);
- rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
- exit(1);
- }
- for (bufsize = (size_t) 32768U;
- setvbuf(batch_file, NULL, _IOFBF, bufsize) != 0 && bufsize > 512;
- bufsize /= 2)
- /* do nothing */ ;
-
- added_first = NULL;
- count = 0;
- in_header = 0;
-
- while (fgets(buf, 511, batch_file) != NULL) {
- if (strnicmp(buf, "#! rnews", 8) == 0)
- in_header = 1;
- if (strcmp(buf, "\n") == 0)
- in_header = 0;
- if ((strnicmp(buf, "Newsgroups:", 11) == 0) && (in_header == 1)) {
- if (verbose)
- fprintf(stderr, "\rArticle %d", ++count);
- already_junked = 0;
- nglist[0] = '\0';
- strcpy(junk_test, buf + 11);
-
- if (!CrossPostToJunk) {
- p = strtok(junk_test, " \t\n\r,:");
- while (p != '\0') {
- gp = find_news_group(p, &junk_flag);
- if (junk_flag == 0) { /* posting to active group */
- already_junked = 1;
- break;
- }
- p = strtok(NULL, " \t\n\r,:");
- }
- }
- strcpy(junk_test, buf + 11);
- p = strtok(junk_test, " \t\n\r,:");
- if (already_junked == 1) {
- nglist[0] = '\0';
- }
- else {
- while (p != '\0') {
- gp = find_news_group(p, &junk_flag);
- if (junk_flag != 0)
- strcat(nglist, p);
- p = strtok(NULL, " \t\n\r,:");
- if ((p != '\0') && (junk_flag != 0))
- strcat(nglist, ",");
- }
- }
-
- p = strtok(nglist, " \t\r\n,:");
- while (p != '\0') {
- /* we now have a new newsgroup in p */
- addnew(p);
- p = strtok(NULL, " \t\n\r,:");
- }
- }
- }
- gp = gp; /* suppress BCC error message */
- fclose(batch_file);
- close_active_file();
-
- putch('\n');
- putch('\r');
- listnew(t);
- addem();
- freeadd();
- }
-
- int addnew(char *p)
- {
- if (added_first != NULL) {
- added = added_first;
- if (stricmp(added->name, p) == 0)
- return 0; /* In first place in table */
-
- if (added->next != NULL) {
- do {
- added = added->next;
- if (stricmp(added->name, p) == 0)
- return 0; /* Already in table */
- }
- while (added->next != NULL);
- }
- }
- /* if here p not in table */
-
- if (added_first == NULL) {
- added_first = (NEW_GROUP *) malloc(sizeof(NEW_GROUP));
- if (added_first == NULL) {
- fprintf(stderr, "unbatch: Out of memory.\n");
- rmlock(my_stuff.news_dir, "history", "Unbatch");
- rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
- exit(1);
- }
- added_first->next = NULL;
- added = added_first;
- }
- else {
- while (added->next != NULL)
- added = added->next;
- added->next = (NEW_GROUP *) malloc(sizeof(NEW_GROUP));
- if (added->next == NULL) {
- fprintf(stderr, "unbatch: out of memory.\n");
- rmlock(my_stuff.news_dir, "history", "Unbatch");
- rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
- exit(1);
- }
- added = added->next;
- }
-
- added->next = NULL;
- strcpy(added->name, p);
- added->answer = 0;
-
- return 1; /* added */
- }
-
- void listnew(int t)
- {
-
- char ch;
-
- added = added_first;
- if (added == NULL)
- return; /* none to list */
-
- do {
- fprintf(stderr, "\nNew Group \"%s\" ", added->name);
- if (t == 2) {
- fprintf(stderr, "Add (Y/N) ? ");
- ch = getch();
- putch(ch);
- ch = tolower(ch);
- if (ch != 'y')
- added->answer = 1;
- }
- added = added->next;
- }
- while (added != NULL);
-
- putch('\n');
- putch('\r');
-
- }
-
- void addem(void)
- {
- int ret;
-
- added = added_first;
- if (added == NULL)
- return;
-
- do {
- if (added->answer == 0) {
- #ifdef ATARI
- ret = spawnlpe(P_WAIT, "addgroup", "addgroup", added->name, NULL, environ);
- #else
- ret = spawnlp(P_WAIT, "addgroup.exe", "addgroup.exe", added->name, NULL);
- #endif
- if (ret == -1) {
- fprintf(stderr, "\nError running \"addgroup %s\"\n", added->name);
- }
- }
- added = added->next;
- }
- while (added != NULL);
- putch('\n');
- putch('\r');
-
-
- }
-
-
- void freeadd()
- {
-
- NEW_GROUP *next;
-
- added = added_first;
- if (added == NULL)
- return;
-
- do {
- next = added->next;
- free(added);
- if (next != NULL) {
- added = next;
- }
- }
- while (next != NULL);
- }
-
- #ifndef __TURBOC__
- #ifndef ATARI
- unsigned long farcoreleft(void)
- {
-
- union _REGS inregs, outregs;
-
- _heapmin();
- inregs.h.ah = 0x48;
- inregs.x.bx = 0xffff;
- _intdos(&inregs, &outregs);
-
- return (16l * (long)outregs.x.bx);
- }
-
- unsigned long testcoreleft(void)
- {
-
- union _REGS inregs, outregs;
-
- inregs.h.ah = 0x48;
- inregs.x.bx = 0xffff;
- _intdos(&inregs, &outregs);
-
- return (16l * (long)outregs.x.bx);
- }
-
- #endif
- #endif
-